{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "DQN中有两个关键技术，一个是经验回放，一个是双网络结构（策略网络和目标网络）。DQN算法通过贪婪法直接获得目标Q值，贪婪法通过最大化的方式使Q值快速向可能的优化目标收敛，但是这容易导致过估计Q值的问题，使得模型具有较大的偏差。因此为了避免这种情况的出现，提出了Double DQN算法，采用Double DQN算法解耦动作的选择和目标Q值的计算，以解决过估计Q值的问题。"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 定义模型\n",
    "\n",
    "Double DQN除了在更新时对期望Q值的近似方式与DQN不同之外，其他都是相同的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "class Model(nn.Module):\n",
    "    def __init__(self, n_states,n_actions,hidden_dim=256):\n",
    "        \"\"\" 初始化q网络，为全连接网络\n",
    "        \"\"\"\n",
    "        super(Model, self).__init__()\n",
    "        self.fc1 = nn.Linear(n_states, hidden_dim) # 输入层\n",
    "        self.fc2 = nn.Linear(hidden_dim,hidden_dim) # 隐藏层\n",
    "        self.fc3 = nn.Linear(hidden_dim, n_actions) # 输出层\n",
    "        \n",
    "    def forward(self, x):\n",
    "        # 各层对应的激活函数\n",
    "        x = F.relu(self.fc1(x)) \n",
    "        x = F.relu(self.fc2(x))\n",
    "        return self.fc3(x)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 定义经验回放"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Experience Replay(ER)在RL中应用很广泛，在off-policy的方法中经验回放的使用极大的提高了样本的利用率和学习的效率。Experience Replay设计的相关方法，包括最开始DQN开始使用ER，然后是16年的PER（Prioritized Experience Replay），2017年NIPS的HER（Hindsight Experience Replay），以及19年ICLR的CER（Competitive Experience Replay）。最早DQN使用了经验回放的方法，在使用ER前，数据样本间的相关性很大，这对于神经网络的学习是不利的，因此希望能够解决经验数据相关性以及非平稳分布的问题，使用经验回放也就自然而然，同时可以更加高效的利用数据。\n",
    "经验回放首先是具有一定容量的，只有存储一定的transition网络才会更新，否则就退回到了之前的逐步跟新了。另外写经验回放的时候，一般需要包含两个功能或方法，一个是push，即将一个transition样本按顺序放到经验回放中，如果满了就把最开始放进去样本挤掉。另外一个是sample,就是随机采样出一个或若干个样本供DQN网络更新。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "from collections import deque\n",
    "import random\n",
    "class ReplayBuffer(object):\n",
    "    def __init__(self, capacity: int) -> None:\n",
    "        self.capacity = capacity\n",
    "        self.buffer = deque(maxlen=self.capacity)\n",
    "    def push(self,transitions):\n",
    "        ''' 存储transition到经验回放中\n",
    "        '''\n",
    "        self.buffer.append(transitions)\n",
    "    def sample(self, batch_size: int, sequential: bool = False):\n",
    "        if batch_size > len(self.buffer): # 如果批量大小大于经验回放的容量，则取经验回放的容量\n",
    "            batch_size = len(self.buffer)\n",
    "        if sequential: # 顺序采样\n",
    "            rand = random.randint(0, len(self.buffer) - batch_size)\n",
    "            batch = [self.buffer[i] for i in range(rand, rand + batch_size)]\n",
    "            return zip(*batch)\n",
    "        else: # 随机采样\n",
    "            batch = random.sample(self.buffer, batch_size)\n",
    "            return zip(*batch)\n",
    "    def clear(self):\n",
    "        ''' 清空经验回放\n",
    "        '''\n",
    "        self.buffer.clear()\n",
    "    def __len__(self):\n",
    "        ''' 返回当前存储的量\n",
    "        '''\n",
    "        return len(self.buffer)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 定义策略"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "首先我们知道目前所有基于深度神经网络的更新方式都是梯度下降，如下：\n",
    "$$\n",
    "\\theta_i \\leftarrow \\theta_i - \\lambda \\nabla_{\\theta_{i}} L_{i}\\left(\\theta_{i}\\right)\n",
    "$$\n",
    "那么这个$\\theta$又是什么呢，注意到前面我们讲的DQN跟Q learning算法的一个主要区别就是使用神经网络替代了Q表，而这个$\\theta$实际上就是神经网络的参数，通常用$Q\\left(s_{i}, a_{i} ; \\theta\\right)$表示。根据强化学习的原理我们需要优化的是对应状态下不同动作的长期价值，然后每次选择价值最大对应的动作就能完成一条最优策略，使用神经网络表示Q表时也是如此，我们将输入的状态数作为神经网络的输入层，动作数作为输出层，这样的神经网络表达的功能就跟在Q learning中的Q表是一样的，只不过具有更强的鲁棒性。我们目前讲了参数的更新过程，但是最关键的是损失是如何计算的，在DQN中损失的计算相对来说比较简单，如下：\n",
    "$$\n",
    "L(\\theta)=\\left(y_{i}-Q\\left(s_{i}, a_{i} ; \\theta\\right)\\right)^{2}\n",
    "$$\n",
    "这里的$y_{i}$通常称为期望值，$Q\\left(s_{i}, a_{i} ; \\theta\\right)$称为实际值，这个损失在深度学习中通常称作均方差损失，也就是mseloss，使用这个损失函数通常追溯到数学上的最小二乘法，感兴趣的同学可以了解一下深度学习中的各种损失函数以及各自的使用场景。在DQN中，目标Q值的计算公式如下，$y_{i}$在DQN中一般表示如下：\n",
    "$$\n",
    "y_{i}= \\begin{cases}r_{i} & \\text {对于终止状态} s_{i+1} \\\\ r_{i}+\\gamma \\max _{a^{\\prime}} Q\\left(s_{i+1}, a^{\\prime} ; \\theta\\right) & \\text {对于非终止状态} s_{i+1}\\end{cases}\n",
    "$$\n",
    "该公式的意思就是将下一个状态对应的最大Q值作为实际值（因为实际值通常不能直接求得，只能近似），这种做法实际上只是一种近似，可能会导致过估计等问题。\n",
    "而在Double DQN中，它不直接通过最大化的方式选取目标网络计算的所有可能 Q 值，而是首先通过估计网络选取最大 Q 值对应的动作。目标Q值的最终表示形式如下：\n",
    "$$\n",
    "y_{t}^{DDQN} = r_{t+1} + \\gamma Q\\left(s_{t+1}, \\text{argmax}{a} Q\\left(s_{t+1}, a; \\theta_t\\right); \\theta_{t}^{\\prime}\\right)\n",
    "$$\n",
    "其中，$r_{t+1}$ 是智能体在时刻 $t$ 执行动作 $a_t$ 后获得的实际奖励；$s_{t+1}$ 是智能体在执行动作 $a_t$ 后转移到的下一个状态；$\\gamma$ 是折扣因子；$Q\\left(s_{t+1}, \\text{argmax}{a} Q\\left(s{t+1}, a; \\theta_t\\right); \\theta_{t}^{\\prime}\\right)$ 表示使用当前策略 $\\text{argmax}{a} Q\\left(s{t+1}, a; \\theta_t\\right)$ 计算在下一个状态 $s_{t+1}$ 时的最大动作价值，而这个最大动作价值是使用目标网络 $\\theta_{t}^{\\prime}$ 来计算的。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import torch.optim as optim\n",
    "import math\n",
    "import numpy as np\n",
    "\n",
    "class Policy(object):\n",
    "    def __init__(self,cfg):\n",
    "        self.action_dim = cfg.action_dim\n",
    "        self.device = torch.device(cfg.device) \n",
    "        self.gamma = cfg.gamma  # 折扣因子\n",
    "        # e-greedy策略相关参数\n",
    "        self.sample_count = 0  # 用于epsilon的衰减计数\n",
    "        self.epsilon = cfg.epsilon_start\n",
    "        self.update_cnt = 0  \n",
    "        self.epsilon_start = cfg.epsilon_start\n",
    "        self.epsilon_end = cfg.epsilon_end\n",
    "        self.epsilon_decay = cfg.epsilon_decay\n",
    "        self.batch_size = cfg.batch_size\n",
    "        self.target_update = cfg.target_update\n",
    "        self.policy_net = Model(cfg.state_dim,cfg.action_dim,hidden_dim=cfg.hidden_dim).to(self.device)\n",
    "        self.target_net = Model(cfg.state_dim,cfg.action_dim,hidden_dim=cfg.hidden_dim).to(self.device)\n",
    "         # 复制参数到目标网络\n",
    "        for target_param, param in zip(self.target_net.parameters(),self.policy_net.parameters()): \n",
    "            target_param.data.copy_(param.data)\n",
    "        # self.target_net.load_state_dict(self.policy_net.state_dict()) # or use this to copy parameters\n",
    "        self.optimizer = optim.Adam(self.policy_net.parameters(), lr=cfg.lr)  # 优化器\n",
    "        self.memory = ReplayBuffer(cfg.buffer_size) # 经验回放\n",
    "\n",
    "    def sample_action(self, state):\n",
    "        ''' 采样动作\n",
    "        '''\n",
    "        self.sample_count += 1\n",
    "        # epsilon指数衰减\n",
    "        self.epsilon = self.epsilon_end + (self.epsilon_start - self.epsilon_end) * \\\n",
    "            math.exp(-1. * self.sample_count / self.epsilon_decay) \n",
    "        if random.random() > self.epsilon:\n",
    "            with torch.no_grad():\n",
    "                state = torch.tensor(state, device=self.device, dtype=torch.float32).unsqueeze(dim=0)\n",
    "                q_values = self.policy_net(state)\n",
    "                action = q_values.max(1)[1].item() # choose action corresponding to the maximum q value\n",
    "        else:\n",
    "            action = random.randrange(self.action_dim)\n",
    "        return action\n",
    "    @torch.no_grad() # 不计算梯度，该装饰器效果等同于with torch.no_grad()：\n",
    "    def predict_action(self, state):\n",
    "        ''' 预测动作\n",
    "        '''\n",
    "        state = torch.tensor(state, device=self.device, dtype=torch.float32).unsqueeze(dim=0)\n",
    "        q_values = self.policy_net(state)\n",
    "        action = q_values.max(1)[1].item() # choose action corresponding to the maximum q value\n",
    "        return action\n",
    "    def update(self):\n",
    "        if len(self.memory) < self.batch_size: # 当经验回放中不满足一个批量时，不更新策略\n",
    "            return\n",
    "        # 从经验回放中随机采样一个批量的转移(transition)\n",
    "        state_batch, action_batch, reward_batch, next_state_batch, done_batch = self.memory.sample(\n",
    "            self.batch_size)\n",
    "        # 将数据转换为tensor\n",
    "        state_batch = torch.tensor(np.array(state_batch), device=self.device, dtype=torch.float)\n",
    "        action_batch = torch.tensor(action_batch, device=self.device).unsqueeze(1)  \n",
    "        reward_batch = torch.tensor(reward_batch, device=self.device, dtype=torch.float).unsqueeze(1)    \n",
    "        next_state_batch = torch.tensor(np.array(next_state_batch), device=self.device, dtype=torch.float)\n",
    "        done_batch = torch.tensor(np.float32(done_batch), device=self.device).unsqueeze(1)\n",
    "        q_value_batch = self.policy_net(state_batch).gather(dim=1, index=action_batch) # 实际的Q值\n",
    "        next_q_value_batch = self.policy_net(next_state_batch) # 下一个状态对应的实际策略网络Q值\n",
    "        next_target_value_batch = self.target_net(next_state_batch) # 下一个状态对应的目标网络Q值\n",
    "        # 将策略网络Q值最大的动作对应的目标网络Q值作为期望的Q值\n",
    "        next_target_q_value_batch = next_target_value_batch.gather(1, torch.max(next_q_value_batch, 1)[1].unsqueeze(1))\n",
    "        expected_q_value_batch = reward_batch + self.gamma * next_target_q_value_batch* (1-done_batch) # 期望的Q值\n",
    "        # 计算损失\n",
    "        loss = nn.MSELoss()(q_value_batch, expected_q_value_batch)\n",
    "        # 优化更新模型\n",
    "        self.optimizer.zero_grad()  \n",
    "        loss.backward()\n",
    "        # clip防止梯度爆炸\n",
    "        for param in self.policy_net.parameters():  \n",
    "            param.grad.data.clamp_(-1, 1)\n",
    "        self.optimizer.step() \n",
    "        # 每隔一段时间，将策略网络的参数复制到目标网络\n",
    "        self.update_cnt += 1\n",
    "        if self.update_cnt % self.target_update == 0: # 每隔一段时间，将策略网络的参数复制到目标网络\n",
    "            self.target_net.load_state_dict(self.policy_net.state_dict())   "
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. 定义训练和测试"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [],
   "source": [
    "import gymnasium as gym\n",
    "\n",
    "def train(cfg):\n",
    "    ''' 训练\n",
    "    '''\n",
    "    env = gym.make(cfg.env_id)\n",
    "    setattr(cfg, \"action_space\", env.action_space)\n",
    "    setattr(cfg, \"state_dim\", env.observation_space.shape[0])\n",
    "    setattr(cfg, \"action_dim\", env.action_space.n)\n",
    "    policy = Policy(cfg)\n",
    "    rewards = []  # 记录所有回合的奖励\n",
    "    frames = []\n",
    "    for i_ep in range(cfg.train_eps):\n",
    "        ep_reward = 0  # 记录一回合内的奖励\n",
    "        ep_step = 0\n",
    "        state, info = env.reset(seed = cfg.seed)  # 重置环境，返回初始状态\n",
    "        for _ in range(cfg.max_steps):\n",
    "            ep_step += 1\n",
    "            action = policy.sample_action(state)  # 选择动作\n",
    "            next_state, reward, done, truncated, info = env.step(action)  # 更新环境，返回transition\n",
    "            policy.memory.push((state, action, reward,next_state, done))  # 保存transition\n",
    "            state = next_state  # 更新下一个状态\n",
    "            policy.update()  # 更新智能体\n",
    "            ep_reward += reward  # 累加奖励\n",
    "            if done:\n",
    "                break\n",
    "        frames.append(i_ep)\n",
    "        rewards.append(ep_reward)\n",
    "        if (i_ep + 1) % 10 == 0:\n",
    "            print(f\"回合：{i_ep+1}/{cfg.train_eps}，奖励：{ep_reward:.2f}，Epislon：{policy.epsilon:.3f}\")\n",
    "    env.close()\n",
    "    return {'rewards':rewards, 'frames':frames}\n",
    "\n",
    "def test(cfg, env, agent):\n",
    "    print(\"开始测试！\")\n",
    "    rewards = []  # 记录所有回合的奖励\n",
    "    steps = []\n",
    "    for i_ep in range(cfg.test_eps):\n",
    "        ep_reward = 0  # 记录一回合内的奖励\n",
    "        ep_step = 0\n",
    "        state, info = env.reset(seed = cfg.seed)  # 重置环境，返回初始状态\n",
    "        for _ in range(cfg.max_steps):\n",
    "            ep_step+=1\n",
    "            action = agent.predict_action(state)  # 选择动作\n",
    "            next_state, reward, done, truncated , info = env.step(action)  # 更新环境，返回transition\n",
    "            state = next_state  # 更新下一个状态\n",
    "            ep_reward += reward  # 累加奖励\n",
    "            if done:\n",
    "                break\n",
    "        steps.append(ep_step)\n",
    "        rewards.append(ep_reward)\n",
    "        print(f\"回合：{i_ep+1}/{cfg.test_eps}，奖励：{ep_reward:.2f}\")\n",
    "    print(\"完成测试\")\n",
    "    env.close()\n",
    "    return {'rewards':rewards}"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.定义环境"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [],
   "source": [
    "import gymnasium as gym\n",
    "import os\n",
    "def all_seed(env,seed = 1):\n",
    "    ''' 万能的seed函数\n",
    "    '''\n",
    "    if seed == 0: # 不设置seed\n",
    "        return \n",
    "    np.random.seed(seed)\n",
    "    random.seed(seed)\n",
    "    torch.manual_seed(seed) # config for CPU\n",
    "    torch.cuda.manual_seed(seed) # config for GPU\n",
    "    os.environ['PYTHONHASHSEED'] = str(seed) # config for python scripts\n",
    "    # config for cudnn\n",
    "    torch.backends.cudnn.deterministic = True\n",
    "    torch.backends.cudnn.benchmark = False\n",
    "    torch.backends.cudnn.enabled = False\n",
    "def env_agent_config(cfg):\n",
    "    env = gym.make(cfg.env_name) # 创建环境\n",
    "    all_seed(env,seed=cfg.seed)\n",
    "    n_states = env.observation_space.shape[0]\n",
    "    n_actions = env.action_space.n\n",
    "    print(f\"状态空间维度：{n_states}，动作空间维度：{n_actions}\")\n",
    "    # 更新n_states和n_actions到cfg参数中\n",
    "    setattr(cfg, 'n_states', n_states)\n",
    "    setattr(cfg, 'n_actions', n_actions) \n",
    "    agent = DoubleDQN(cfg)\n",
    "    return env,agent"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 设置参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "class Config:\n",
    "    def __init__(self):\n",
    "        self.algo_name = 'DoubleDQN' # 算法名称\n",
    "        self.env_id = 'CartPole-v1' # 环境名称\n",
    "        self.mode = 'train'\n",
    "        self.seed = 1 # 随机种子\n",
    "        self.train_eps = 100 # 训练回合数\n",
    "        self.max_steps = 200 # 每回合最大步数\n",
    "        self.gamma = 0.99 # 折扣因子\n",
    "        self.lr = 0.0001 # 学习率\n",
    "        self.epsilon_start = 0.95 # epsilon初始值\n",
    "        self.epsilon_end = 0.01 # epsilon最终值\n",
    "        self.epsilon_decay = 500 # epsilon衰减率\n",
    "        self.buffer_size = 10000 # ReplayBuffer容量\n",
    "        self.batch_size = 64 # ReplayBuffer中批次大小\n",
    "        self.target_update = 100 # 目标网络更新频率\n",
    "        self.hidden_dim = 256 # 神经网络隐藏层维度\n",
    "        self.device = 'cpu' if not torch.cuda.is_available() else 'cuda' # 设备选择\n",
    "\n",
    "\n"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5.开始训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hyperparameters:\n",
      "================================================================================\n",
      "        Name        \t       Value        \t        Type        \n",
      "     algo_name      \t     DoubleDQN      \t   <class 'str'>    \n",
      "       env_id       \t    CartPole-v1     \t   <class 'str'>    \n",
      "        mode        \t       train        \t   <class 'str'>    \n",
      "        seed        \t         1          \t   <class 'int'>    \n",
      "     train_eps      \t        100         \t   <class 'int'>    \n",
      "     max_steps      \t        200         \t   <class 'int'>    \n",
      "       gamma        \t        0.99        \t  <class 'float'>   \n",
      "         lr         \t       0.0001       \t  <class 'float'>   \n",
      "   epsilon_start    \t        0.95        \t  <class 'float'>   \n",
      "    epsilon_end     \t        0.01        \t  <class 'float'>   \n",
      "   epsilon_decay    \t        500         \t   <class 'int'>    \n",
      "    buffer_size     \t       10000        \t   <class 'int'>    \n",
      "     batch_size     \t         64         \t   <class 'int'>    \n",
      "   target_update    \t        100         \t   <class 'int'>    \n",
      "     hidden_dim     \t        256         \t   <class 'int'>    \n",
      "       device       \t        cpu         \t   <class 'str'>    \n",
      "================================================================================\n",
      "回合：10/100，奖励：19.00，Epislon：0.638\n",
      "回合：20/100，奖励：10.00，Epislon：0.495\n",
      "回合：30/100，奖励：12.00，Epislon：0.392\n",
      "回合：40/100，奖励：9.00，Epislon：0.319\n",
      "回合：50/100，奖励：10.00，Epislon：0.261\n",
      "回合：60/100，奖励：13.00，Epislon：0.202\n",
      "回合：70/100，奖励：39.00，Epislon：0.118\n",
      "回合：80/100，奖励：63.00，Epislon：0.046\n",
      "回合：90/100，奖励：145.00，Epislon：0.016\n",
      "回合：100/100，奖励：200.00，Epislon：0.010\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAioAAAHJCAYAAACrCBICAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAACh/klEQVR4nOzdd3yT1f7A8c+T2ZnuBWWVvcpGNshFRC+i4rpXxYXXiQMH7r0VFRG54ERRrxMn/kTFrYBM2Xt375k26/n9kSZtOtM2TVv4vl8vXtDkyfOcnIbkm3O+53sUVVVVhBBCCCHaIE1rN0AIIYQQoi4SqAghhBCizZJARQghhBBtlgQqQgghhGizJFARQgghRJslgYoQQggh2iwJVIQQQgjRZkmgIoQQQog2SwKVdkRq8wkhhLwXnmwkUGknVq9ezV133eWTc61YsYLevXtz/PjxFn2MOLksW7aMsWPHkpyczOLFi2s9pnfv3h5/+vXrxymnnMJVV13FTz/91GJtu/vuu5k8eXK9x7z88sv07t27Ued1/b+o+mfgwIFMnjyZBx54gPT09Fofl5OTw4svvsg///lPBg8ezOjRo7n88sv55ptv6rzG448/3uR2p6enc8kllzBw4EBGjx6N2Wxu1PP01qFDh3j44YeZMmUKycnJTJo0idtuu43du3f77BrV3wuPHz9e43fQp08fhgwZwsyZM/nkk08afY3evXvz8ssv+6zN3vrxxx8b/Ro8GehauwHCO8uWLfPZuSZNmsSHH35IbGxsiz5GnDyKi4t55plnmDRpEldddRWJiYl1Hnv++edzwQUXAGC1WsnKyuLTTz/luuuu47777uOyyy7zV7N9ZtGiRcTExABgNpvZt28fr776Kj/88AMffvghnTt3dh+7c+dOrr32WrRaLZdffjn9+vWjqKiI1atXc/vtt7Nq1Srmz5+PXq/3uMZ7773HtGnTGD58eKPb9/bbb7Nlyxaee+454uLiCAwMbN4TrsV3333HvHnz6NmzJ9dffz2JiYmkp6fz9ttvc+GFF/Lf//6XsWPHNvs6db0XXn/99UyaNAlwjriUlJTw8ccfc99992Gz2fjXv/7V7Gu3pHXr1nH77be3djPaJAlUTkKRkZFERka2+GPEyaOgoACHw8GUKVMYMWJEvcfGx8czePBgj9vOPPNMbrrpJp599lkmT55cb6DTFvXt29ejzaNHj2by5MnMnDmThx56iLfeeguA0tJSbrnlFiIjI3nnnXcICwtzP2bKlCmceuqp3HTTTXTr1o1bb73V4xohISHce++9fPnllwQEBDSqffn5+cTGxnLmmWc2/UnW4+jRo9x1112MHz+eBQsWoNVq3fdNnTqVf//739x11138+OOPGAyGFmlD586da7yuxowZw+7du1m2bFmbDVSKi4t57bXXeO211wgNDaW0tLS1m9TmyNRPOzBr1iz++usv/vrrL3r37s26detYt24dvXv35oMPPuDUU09l6NCh/PHHHwB8/PHHzJw5k8GDB5OcnMzZZ5/N//3f/7nPV30a5+677+aKK67g008/5fTTT2fAgAGcffbZ/Prrr816DMDmzZu55JJLGDx4MJMmTeLtt9/miiuu4O677673OW/ZsoWrrrqKoUOHMmrUKG677TYyMjJqbYvL5MmTPc7bu3dvFi1axMyZM0lOTmbRokX07duXd9991+Nxubm59O/f3/1NzeFw8Oqrr3LaaacxYMAATj/9dJYvX97g76moqIinnnqKKVOmMHDgQKZPn15j2Hny5MksXLiQZ555hjFjxpCcnMzs2bM5fPhwvee2WCwsWLCAf/zjHyQnJzN9+nQ+++wz9/2zZs3i7rvvZsmSJYwZM4Zhw4Zxww03kJKS4j6mtukP17D5ihUr6r3+H3/8wcUXX8ywYcM45ZRTuP3220lLSwOcvw/Xee+9994mD13PnTsXq9Xq0Wfe9Gltw/R1TYd8+OGHTJo0ieTkZC6//HJ27txZb5t++OEHZs6cycCBAxk7diyPP/641x8kiYmJXHTRRfz5558cPXoUgK+//pqjR4/y8MMPewQpLlOnTuXMM89k2bJllJSUeNx31113cfToUV544QWvru8yefJkVqxYQWpqqkdfZWZmcs899zBx4kSSk5M5//zzWb16tcdja/s/VJvly5djsVi4//77PYIUgMDAQO666y7OO+88CgoKALDb7bz66qtMnz6d5ORkBg8ezL/+9S/Wrl3rftzLL7/MaaedxqJFixg5ciTjxo1jxowZNd4L66PRaOjbty+pqanu27x5TVWXn5/Pgw8+yJgxYxg4cCAXXngha9asqfcxmzZtonfv3jWmNHft2kXv3r35/vvvAfjkk0/46KOPePDBB7n00kvrPefJSgKVduChhx6iX79+9OvXjw8//JD+/fu771u0aBF33XUXDz74IEOGDOG9997jwQcfZMqUKSxdupT58+djMBi444476pwvB9i+fTtvvPEGN998M6+88gparZabbrrJ/cbSlMccOHCAK664AoAXXniBm266iVdffZWNGzfW+3x37tzJpZdeSnl5Oc8++yyPPPII27dvZ/bs2dhstkb0HCxZsoSzzjqLhQsXcvrppzNy5EhWrlzpccy3336Lqqr885//BODhhx9m4cKFzJgxgyVLljBt2jSefPJJXnnllTqvU1ZWxsUXX8xXX33F1VdfzeLFixk2bBj33XcfS5Ys8Tj2nXfe4eDBgzz11FM8/vjjbN++vcH8ozvuuIO33nqLCy64gKVLlzJu3Djuvvtuvv76a/cxq1evZsWKFdx///088sgj7Nq1i1mzZjU7H+Hzzz/nqquuIiEhgRdeeIF77rmHzZs3c9FFF5GTk8OkSZPcH2DXX389H374YZOuk5SURIcOHdyvj8b0qTfS09NZtGgRt956Ky+88AIFBQXMmjXL40Osqq+++oobb7yRpKQkXnnlFebMmcOXX37JDTfc4HUyp2uqw/WcfvzxR6KjoxkyZEidj/nnP/+J2Wx2f/FwGTVqFBdddBHLly9v8P9QVYsWLWLixInExMTw4YcfcsEFF5Cdnc3555/Phg0bmDt3Li+//DIdO3bkxhtv5Msvv/R4fPX/Q7X57bff6NevH3FxcbXeP3r0aObOneueHps/fz6LFy/moosu4vXXX+exxx4jPz+fW265xeP1mpqayi+//MKLL77IPffcwwsvvFDne2FdDh065J56a8prqry8nMsvv5zVq1czd+5cFi1aRHx8PFdffXW9wcrQoUPp3Llzjfebr7/+mvDwcCZOnAg4A8kff/yxzY74tAUy9dMO9OjRg5CQEIAaQ5sXX3wx06ZNc/987NgxZs+ezQ033OC+rWPHjsycOZONGze6P4yrKyoqYsWKFe7/0EFBQVx66aWsXbu2zjenhh6zdOlSQkNDef31191z4klJSQ3+h1yyZAnh4eG8+eabGI1GAGJjY7n99tvZt29fvY+tbvjw4Vx55ZXun88++2zuvfdeUlNT6dChAwArV65kzJgxxMTEcOjQIT766CNuu+02rrnmGgDGjRuHoigsXbqUiy++mIiIiBrXWbFiBXv37uWDDz5wfwiNHz8em83G4sWL+de//kV4eDgAJpOJxYsXu795Hj16lJdffpm8vLxaz713715WrVrFvffey+WXXw443/hTUlJYt24d06dPB5y5EStWrKBTp06As6/PPfdcPv/8c/797383qt9cHA4H8+fPZ9y4cTz//PPu24cOHcqZZ57JG2+8wbx58+jbty9Q+/B7Y0RHR5OdnQ00rk+9YbfbeeWVV0hOTgZg0KBBTJkyheXLl9cIFFVVZf78+YwfP5758+e7b+/atStXXHEFv/zyizsfoj6uD+asrCwAUlJS6NixY72Pcf1/qjoa5jJv3jx+++037r33Xr744guvpoD69etHZGQkBoPB/bt57rnnyM3NZdWqVe72TJw4kSuuuIJnn32W6dOno9E4v8dW/z9Um/T0dPdrwBuZmZnMnTuXWbNmuW8zGo3cdNNN7Nmzx91Om83GXXfd5ZGXU/29MD8/H3C+Vl1fZBwOBxkZGSxfvpzdu3fz8MMPA017TX3xxRfs3r2bjz76iEGDBgEwYcIEZs2axfz58/n000/rfJ4zZszgzTffpKysjICAAFRV5ZtvvmHatGnuKbCq+UuidjKi0s5Vf3O4++67ueOOOygsLGTLli188cUXvPfee4Bz+qAukZGRHv9h4uPjAer9Nt7QY9auXcuECRM8EveGDBnS4Bv1xo0bmTBhgjtIcT3uxx9/bNSbIdTsn6lTp2I0Gt2rK9LS0ti4cSNnn322u82qqjJ58mRsNpv7z+TJkykvL6/zm+xff/1Fx44da3xTnjFjBuXl5fz999/u2wYOHOgxPN5QX7uuOXXqVI/bX375ZR577DH3z0OHDnUHKeD8gOrUqRPr16+v9bzeOHToEFlZWe5gyKVz584MGTKEv/76q8nnro2qqiiKAjSuT73RqVMnd5ACziBi8ODBtfbPwYMHSU9Pr/E6GDFiBCEhITVGO+p7PoD7OXnDFSDY7fYa9wUHB/PEE09w+PBhXnzxRa/PWd1ff/1V6//FGTNmkJWVxcGDB923efN/TqvV1treujz//PNcfvnl5ObmsmHDBj799FP3SE719ylv/8/fd9999O/fn/79+zNw4ECmTJnCihUruP7667nooouApr2m1qxZQ0xMDP3793e/Dux2O6eeeirbt29352dVfZ24+mLGjBmUlpa6p382bdpEamqq+/1GeEdGVNq5oKAgj5+P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k40OBhITE3n44Ye57777uOSSS/jXv/5FQkICR48e5a233uLYsWO88cYbGI1GunXrRkhICEuWLEGn06HT6Vi1apV7iXBD71PevBfWpSn/T2fOnMm7777LlVdeyXXXXUdCQgJ//vknr732GpdeemmNwnzVuVb4vP/++wwZMqTRQaCQQKXduOSSS9i+fTv/+c9/eOqpp+qsELt48WKeeOIJ7r77bgwGAz169OC///0vTz75JBs2bPDIsm9pXbp04Y033uDZZ5/l5ptvJioqimuvvZb//ve/9c479+vXj+XLl/P8889z6623EhISwsSJE7njjjswGAwYDAZefvllnn/+eW688UY6duzInDlz+Pzzz71u29lnn83bb7/tsbrB5amnnmLp0qV88MEHpKenExUVxZlnnsmtt95a54d6YGCgu80vvfQSxcXFJCUl8cQTT3D++ed73a66PPfccyxatIi3336bvLw8unfvzsKFCz2G/YcPH86oUaO47777AOc0w7x589zD0GPHjuWuu+5i+fLlrFq1iv79+7No0aIGV2HNnDmT4OBgli5dyo033khISAjjx4/ntttuq3WYvyGffPKJ+0NJo9EQHh7OoEGDeOutt9yjP+B9n95zzz3YbDaeeeYZdDodZ555Jrfffjv333+/x3X79evH6aefzsMPP0xRURGjR4/m3nvvrXPk4oILLiA4OJjXX3+dDz/8kKCgIIYOHcr8+fNr5HfMmTPH/W+9Xk/Hjh057bTTuOaaa2r0katuzTvvvMPHH39MSkoKRqORXr16uWuenHXWWdx999115kq53H333fz++++15tnUJyYmhv/97388//zzPP7441itVvr06cPixYv5xz/+0ahzuZx77rl06dKFt99+mwULFpCTk0NMTAxDhw7l5Zdfpnv37oBzKmXx4sU8++yz3HLLLQQHB7vrG/3nP/9hw4YN9W53UP29sL6l3tU15f9pUFAQ7733Hs8//zzPPfccRUVFdOzYkdtvv52rrrrKq+ueffbZ/PDDD5x11llet1VUUlTZ3Um0EFdCb9W5+MLCQsaMGcO8efPaZan0tsoVgHpTmE60bRaLhc8//5zY2FivlkALcaKTERXRYnbs2MHChQu57bbb6N+/P/n5+bz11luEhobWWO4qhHAyGAxceOGFrd0MIdoMCVREi7nqqquwWCz873//Iy0t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/P33Zt54Yym7d+/CarXQoUNHLrvsKk4//UwAnnjiYcxmMyUlxezYsZ3LL7+KSy65vMHnUt/vVQhxcsitkkwrajopAxVVVSn98gkcGftb5frauJ4EzrjX62AlPz+f++67kzlz5jJmzDgyMzN47LGHWLz4Je6++wEA7HY777zzJg899Dg2m40777yVK664mOnTz+bVV9/mu+/+j9de+y/jxk2ke/cefPTR+yxZsog5c+YyYsQp7Ny5nRdeeIaCggJuueV2SktLuP762XTo0JGnn34evd7Am2++ypw5/2HZsv/xj3+cRnFxMQsXPs8XX3yLyRTG5s0bSU9PY9u2v3nuuZewWi089tiDPP30Y7zyymuoqsqdd96MwRDAM88sICQkhG+/Xcn118/m9dffpnv3Xnz//be88MIz3HLLHQwfPpJff/2JV19dTGxsXL199PXXn/PAA4/Ro0cPoqKi+eKLFSxd+gq33TaPvn37s2/fHl588VmyszO54YZbGD16LOvX/+UOVDZsWIeiKGzatIE+ffphs9lYv/4vHnzwMbKyMrnttjmcd95FzJt3H1arlffee5unn36MESNOITIyCoCff17NDTfczNy58zAajQ0+F29+r0KIE19lVVoZUanNSRmoACi0nyVgWVkZWCwW4uLiiY9PID4+gWeeeQG73e5x3NVXX+ceDRg2bAQ7d27nhhtuRlEUZs26gmXLXufgwf0kJXXn3XffZubMC5k58wIAOnXqTEFBAYsXv8Ts2dfy/fffUlCQzxtvvEtERAQADz/8OBdeeA4rVnzEDTfcQkhICABRUdHuNuh0Oh588DGCg533nX32TF59dTEAGzeuZ/v2baxc+QMmUxgA1157I9u2/c2HH/6Pe+99iE8++ZApU6a623XppVewY8c29u3bW28f9ezZi6lTp7l/fvvtN7jiitlMmXI6AB07JlJSUsLzzz/D7NnXMW7cBB577EEsFgsajYbNmzcxbtxENm3awMUXX8aWLZtwOOyMGDGS7OxsZs++ln//e5Y7uJw160q+/XZlxWiUM1AJDTVx8cWXudvQ0HPx9vcqhDhxlVvtFJul2Ft9TspARVEUAmfc2+DUj06nwdYGpn569uzNlCmnc9ddc4mKimbEiFMYM2Y8EyZM8jguMbGT+9+BgYEkJHRwX8dodEbqVquV/Pw8cnNzSE4e7PH4IUOG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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "import os\n",
    "\n",
    "def smooth(data: list, weight: float = 0.9):\n",
    "    '''用于平滑曲线，类似于Tensorboard中的smooth曲线\n",
    "    '''\n",
    "    last = data[0] \n",
    "    smoothed = []\n",
    "    for point in data:\n",
    "        smoothed_val = last * weight + (1 - weight) * point  # 计算平滑值\n",
    "        smoothed.append(smoothed_val)                    \n",
    "        last = smoothed_val                                \n",
    "    return smoothed\n",
    "\n",
    "def plot_rewards(cfg, frames, rewards):\n",
    "    ''' 画图\n",
    "    '''\n",
    "    sns.set_theme(style=\"darkgrid\")\n",
    "    plt.figure()  # 创建一个图形实例，方便同时多画几个图\n",
    "    plt.title(f\"{cfg.mode}ing curve on {cfg.device} of {cfg.algo_name} for {cfg.env_id}\")\n",
    "    plt.xlabel('frames')\n",
    "    plt.plot(frames, rewards, label='rewards')\n",
    "    plt.plot(frames, smooth(rewards), label='smoothed rewards')\n",
    "    plt.legend()\n",
    "    plt.show()\n",
    "\n",
    "def print_cfgs(cfg):\n",
    "    ''' 打印参数\n",
    "    '''\n",
    "    cfg_dict = vars(cfg)\n",
    "    print(\"Hyperparameters:\")\n",
    "    print(''.join(['=']*80))\n",
    "    tplt = \"{:^20}\\t{:^20}\\t{:^20}\"\n",
    "    print(tplt.format(\"Name\", \"Value\", \"Type\"))\n",
    "    for k,v in cfg_dict.items():\n",
    "        if v.__class__.__name__ == 'list':\n",
    "            v = str(v)\n",
    "        print(tplt.format(k,v,str(type(v))))   \n",
    "    print(''.join(['=']*80))\n",
    "\n",
    "def all_seed(seed: int = 0):\n",
    "    ''' 设置随机种子\n",
    "    '''\n",
    "    if seed == 0:\n",
    "        return\n",
    "    np.random.seed(seed)\n",
    "    random.seed(seed)\n",
    "    torch.manual_seed(seed) # config for CPU\n",
    "    torch.cuda.manual_seed(seed) # config for GPU\n",
    "    os.environ['PYTHONHASHSEED'] = str(seed) # config for python scripts\n",
    "    # config for cudnn\n",
    "    torch.backends.cudnn.deterministic = True\n",
    "    torch.backends.cudnn.benchmark = False\n",
    "    torch.backends.cudnn.enabled = False  \n",
    "\n",
    "# 获取参数\n",
    "cfg = Config() \n",
    "all_seed(cfg.seed)\n",
    "print_cfgs(cfg)\n",
    "res = train(cfg)\n",
    "plot_rewards(cfg, res['frames'], res['rewards'])\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "joyrl",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.14"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
